/****************************** Module Header ******************************\
 * Module Name:  EntityHelper.cs
 * Module Version:  1.0.0 (2011-9-23)
 * Copyright (c) AnyEB.Com (14507247@qq.com)
 * 
 * This class is used to process data entity. It supplies useful method to
 * fill entity by IDataReader.
 * 
 * log:2012-11-30
 * 重构,名称不变
 * 
 * This source is subject to the GPL License.
 * See http://www.gnu.org/licenses/gpl.html.
 * All other rights reserved.
 * 
 * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
 * EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
 * WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.
\***************************************************************************/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Data;
using System.Data.Common;
using System.Text;
using System.IO;
using System.Reflection;

namespace UCL.Data.ORM
{
    /// <summary>
    /// 数据实体设置类
    /// <para>读取SqlDataReader并将值赋给实体类</para>
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class EntityHelper
    {
        /// <summary>
        /// 读取实体类映射并将SqlDataReader读取出来的值赋给实体类
        /// </summary>
        /// <param name="e">实体类</param>
        /// <param name="dr">数据库读取器</param>
        public static void EntityFromDataReader<T>(ref T e, IDataReader dr)
        {
            Type type = e.GetType();
            foreach (PropertyInfo pi in type.GetProperties())
            {
                SetPropertyValue<T>(e, pi, dr[pi.Name]);
            }
        }

        /// <summary>
        /// 根据数据库字段填充数据实体类
        /// </summary>
        /// <param name="e">数据实体类</param>
        /// <param name="dr">数据读取器</param>
        public static void DataReaderToEntity<T>(ref T e, ref  IDataReader dr)
        {
            Type type = e.GetType();
            for (int i = 0; i < dr.FieldCount; i++)
            {
                string name = dr.GetName(i);
                foreach (PropertyInfo pi in type.GetProperties())
                {
                    if (pi.Name == name)
                    {
                        SetPropertyValue<T>(e, pi, dr[name]);
                    }
                }
            }
        }

        /// <summary>
        /// 设置实体对象的值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="e"></param>
        /// <param name="pi"></param>
        /// <param name="oV"></param>
        public static void SetPropertyValue<T>(T e, PropertyInfo pi, object oV)
        {
            if (oV == null || oV == DBNull.Value) return;
            if (pi.PropertyType == typeof(string))
            {
                pi.SetValue(e, oV, null);
                return;
            }
            if (pi.PropertyType.IsGType<Guid>())
            {
                Guid gV;
                if (Guid.TryParse(oV.ToString(), out gV)) pi.SetValue(e, Guid.TryParse(oV.ToString(), out gV) ? gV : Guid.Empty, null);
                return;
            }
            if (pi.PropertyType.IsGType<int>())
            {
                int intV;
                pi.SetValue(e, Int32.TryParse(oV.ToString(), out intV) ? intV : default(int), null);
                return;
            }
            if (pi.PropertyType.IsGType<DateTime>())
            {
                DateTime datV;
                pi.SetValue(e, DateTime.TryParse(oV.ToString(), out datV) ? datV : DateTime.Parse("1900-1-1"), null);
                return;
            }
            if (pi.PropertyType.IsGType<bool>())
            {
                bool blnV;
                pi.SetValue(e, Boolean.TryParse(oV.ToString(), out blnV) ? blnV : default(bool), null);
                return;
            }
            if (pi.PropertyType.IsGType<short>())
            {
                short srtV;
                pi.SetValue(e, short.TryParse(oV.ToString(), out srtV) ? srtV : default(short), null);
                return;
            }
            if (pi.PropertyType.IsGType<decimal>())
            {
                decimal dcmV;
                pi.SetValue(e, decimal.TryParse(oV.ToString(), out dcmV) ? dcmV : default(decimal), null);
                return;
            }
            if (pi.PropertyType.IsGType<double>())
            {
                double dblV;
                pi.SetValue(e, Double.TryParse(oV.ToString(), out dblV) ? dblV : default(double), null);
                return;
            }
            if (pi.PropertyType == typeof(byte[]))
            {
                pi.SetValue(e, (byte[])oV, null);
                return;
            }
            if (pi.PropertyType.IsGType<float>())
            {
                float fltV;
                pi.SetValue(e, float.TryParse(oV.ToString(), out fltV) ? fltV : default(float), null);
                return;
            }
        }

        /// <summary>
        /// 获取指定dll文件中的所有命名空间列表
        /// </summary>
        /// <param name="dllpath"></param>
        /// <returns></returns>
        public static IList<string> GetListOfNameSpacesByDll(string dllpath)
        {
            List<string> list = new List<string>();
            if (!File.Exists(dllpath)) return list;
            Assembly dll = Assembly.LoadFile(dllpath);
            foreach (Type t in dll.GetTypes())
            {
                if (t.Namespace != null && !list.Contains(t.Namespace)) list.Add(t.Namespace);
            }
            return list;
        }

        /// <summary>
        /// 获取指定dll文件中指定命名空间的所有实体名称列表
        /// <para>2012-9-11</para>
        /// </summary>
        /// <param name="dllpath"></param>
        /// <param name="namespacename"></param>
        /// <returns></returns>
        public static IList<string> GetListOfEntityNameByDll(string dllpath, string namespacename = "")
        {
            List<string> list = new List<string>();
            if (!File.Exists(dllpath)) return list;
            Assembly dll = Assembly.LoadFile(dllpath);
            foreach (Type t in dll.GetTypes())
            {
                if (t.Namespace == namespacename)
                {
                    list.Add(t.Name);
                }
            }
            list.Sort();
            return list;
        }

        /// <summary>
        /// 获取指定dll文件中指定命名空间和实体名称的字段列表
        /// </summary>
        /// <param name="dllpath"></param>
        /// <param name="namespacename"></param>
        /// <param name="typename"></param>
        /// <param name="isSort"></param>
        /// <returns></returns>
        public static IList<string> GetListOfFieldNameByDll(string dllpath, string namespacename, string typename, bool isSort = false)
        {
            List<string> list = new List<string>();
            if (!File.Exists(dllpath)) return list;
            Assembly dll = Assembly.LoadFile(dllpath);
            foreach (PropertyInfo pi in dll.GetType(namespacename.Length == 0 ? typename : "{0}.{1}".Fmt(namespacename, typename)).GetProperties())
            {
                list.Add(pi.Name);
            }
            if (isSort) list.Sort();
            return list;
        }

        public static IList<string> GetListOfFieldNameByType<T>(bool isSort = false)
        {
            List<string> list = new List<string>();
            foreach (PropertyInfo pi in typeof(T).GetProperties())
            {
                list.Add(pi.Name);
            }
            if (isSort) list.Sort();
            return list;
        }
        /// <summary>
        /// 获取指定枚举类型的所有枚举值列表
        /// </summary>
        /// <typeparam name="E"></typeparam>
        /// <returns></returns>
        public static IList<string> GetListByEnum<E>()
        {
            IList<string> list = new List<string>();
            foreach (FieldInfo fi in typeof(E).GetFields())
            {
                if (fi.IsSpecialName) continue;
                list.Add(fi.Name);
            }
            return list;
        }

        /// <summary>
        /// 获取dll文件生成的创建数据表的命令
        /// </summary>
        /// <param name="dllpath"></param>
        /// <param name="currentnamespace"></param>
        /// <param name="providerName"></param>
        /// <param name="tables">指定要生成的表名称</param>
        /// <returns></returns>
        public static string GetCreateTableTextInNameSpace(string dllpath, string currentnamespace, string providerName, IList<string> tables)
        {
            if (!File.Exists(dllpath)) return string.Empty;
            Assembly dll = Assembly.LoadFile(dllpath);
            string strSql;
            StringBuilder sbSql = new StringBuilder();
            IDatabaseHelper dbh = new SQLServerHelper("");
            foreach (Type t in dll.GetTypes())
            {
                if (t.Namespace == currentnamespace)
                {
                    if (tables != null && tables.Count > 0 && !tables.Contains(t.Name)) continue;
                    strSql = GetCreateTableTextByType(t, providerName);
                    if (strSql.Length == 0) continue;
                    sbSql.AppendFormat("-- drop table {0};{1}", dbh.SQL_FormatSql("[{0}]").Fmt(t.Name), Environment.NewLine);
                    sbSql.AppendFormat("{0}{1}{1}", strSql, Environment.NewLine);
                }
            }
            return sbSql.ToString();
        }

        /// <summary>
        /// 获取某个命名空间里面的所有类型
        /// </summary>
        /// <param name="dllpath"></param>
        /// <param name="currentnamespace"></param>
        /// <returns></returns>
        /// <remarks>2014-4-2 by sutroon</remarks>
        public static IList<Type> GetTypesInNamespace(string dllpath, string currentnamespace)
        {
            IList<Type> lst = new List<Type>();
            if (!File.Exists(dllpath)) return lst;
            Assembly dll = Assembly.LoadFile(dllpath);
            foreach (Type t in dll.GetTypes())
            {
                if (t.Namespace == currentnamespace)
                {
                    lst.Add(t);
                }
            }
            return lst;
        }

        /// <summary>
        /// 获取指定类型的创建数据表的命令
        /// </summary>
        /// <param name="type"></param>
        /// <param name="providerName"></param>
        /// <returns></returns>
        public static string GetCreateTableTextByType(Type type, string providerName)
        {
            DBTableAttribute attrTable = type.GetCustomAttributes(typeof(DBTableAttribute), false).FirstOrDefault() as DBTableAttribute;
            if (attrTable != null && attrTable.Disabled) return string.Empty; // 如果实体类指示Enable=false则退出数据库创建
            StringBuilder sbFields = new StringBuilder();
            IDatabaseHelper dbh = new SQLServerHelper("");
            string length, dbType, name,strAutoIncrement = dbh.Sql_GetAutoIncrementSql(), sFieldName = dbh.SQL_FormatSql("[{0}]");;
            DBColumnAttribute attrCol;
            foreach (FieldInfo fi in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic))
            {
                name = string.Format(sFieldName, fi.Name.TrimStart('_'));
                attrCol = fi.GetCustomAttributes(typeof(DBColumnAttribute), false).FirstOrDefault() as DBColumnAttribute;
                dbType = attrCol != null && !string.IsNullOrEmpty(attrCol.DbType) ? attrCol.DbType : dbh.ClrTypeToDbTypeName(fi.FieldType);
                length = attrCol != null && !string.IsNullOrEmpty(attrCol.Length) ? attrCol.Length : "255";

                if (attrCol != null && attrCol.IsKey)
                {
                    switch (dbType)
                    {
                        case "varchar":
                        case "nvarchar":
                            sbFields.AppendFormat(" {0} {1}({2}) primary key", name, dbType, length);
                            if (attrCol != null && !string.IsNullOrEmpty(attrCol.DefaultValue)) sbFields.AppendFormat(" default '{0}'", attrCol.DefaultValue);
                            sbFields.Append(",");
                            break;
                        case "uniqueidentifier":
                            sbFields.AppendFormat(" {0} {1} primary key", name, dbType);
                            if (attrCol != null && !string.IsNullOrEmpty(attrCol.DefaultValue)) sbFields.AppendFormat(" default {1}{0}{1}", attrCol.DefaultValue, attrCol.DefaultValue.IndexOf("()") > -1 ? "" : "'");
                            sbFields.Append(",");
                            break;
                        default:
                            sbFields.AppendFormat(" {0} {1} primary key {2},", name, dbType, strAutoIncrement);
                            break;
                    }
                    continue;
                }
                if (dbType == "varchar" || dbType == "nvarchar")
                {

                    sbFields.AppendFormat(" {0} {1}({2})", name, dbType, length);
                    if (attrCol != null && !attrCol.CanBeNull) sbFields.Append(" not null");
                    if (attrCol != null && !string.IsNullOrEmpty(attrCol.DefaultValue)) sbFields.AppendFormat(" default '{0}'", attrCol.DefaultValue);
                    sbFields.Append(",");
                    continue;
                }
                if (dbType == "text" || dbType == "ntext" || dbType == "xml" || dbType == "uniqueidentifier")
                {
                    sbFields.AppendFormat(" {0} {1}", name, dbType);
                    if (attrCol != null && !attrCol.CanBeNull) sbFields.Append(" not null");
                    if (attrCol != null && !string.IsNullOrEmpty(attrCol.DefaultValue)) sbFields.AppendFormat(" default {1}{0}{1}", attrCol.DefaultValue, attrCol.DefaultValue.IndexOf("()") > -1 ? "" : "'");
                    sbFields.Append(",");
                    continue;
                }
                sbFields.AppendFormat(" {0} {1}", name, dbType);
                if (attrCol != null && !attrCol.CanBeNull) sbFields.Append(" not null");
                if (attrCol != null && !string.IsNullOrEmpty(attrCol.DefaultValue)) sbFields.AppendFormat(" default {0}", attrCol.DefaultValue);
                sbFields.Append(",");
            }
            return string.Format("create table {0} ({1});", string.Format(sFieldName, type.Name), sbFields.ToString().TrimEnd(','));
        }

        /// <summary>
        /// 获取由Dll对比数据库的更新语句
        /// </summary>
        /// <param name="dllpath"></param>
        /// <param name="connectionString"></param>
        /// <param name="providerName"></param>
        /// <param name="currentnamespace"></param>
        /// <param name="tables"></param>
        /// <returns></returns>
        public static string GetUpdateTableTextByDll(string dllpath, string connectionString, string providerName, string currentnamespace, IList<string> tables)
        {
            if (!File.Exists(dllpath)) return string.Empty;
            IDatabaseHelper dbh = new SQLServerHelper(connectionString);
            Assembly dll = Assembly.LoadFile(dllpath);
            string strSql;
            StringBuilder sbSql = new StringBuilder();
            IList<string> list = dbh.SO_GetTables();
            DBTableAttribute attrTable;
            foreach (Type t in dll.GetTypes())
            {
                if (t.Namespace == currentnamespace)
                {
                    // 过滤dll中的不相干类型
                    if (tables != null && tables.Count > 0 && !tables.Contains(t.Name)) continue;
                    // 检测实体对象是否可用
                    attrTable = t.GetCustomAttributes(typeof(DBTableAttribute), false).FirstOrDefault() as DBTableAttribute;
                    if (attrTable != null && attrTable.Disabled) continue;
                    // 表已存在,比较字段
                    if (list.Contains(t.Name))
                    {
                        sbSql.Append(GetUpdateTableTextByType(t, connectionString, providerName));
                        list.Remove(t.Name);
                        continue;
                    }
                    // 表未存在,创建新表
                    strSql = GetCreateTableTextByType(t, providerName);
                    if (strSql.Length == 0) continue;
                    sbSql.AppendFormat("{0};{1}{1}", strSql.TrimEnd(';'), Environment.NewLine);
                }
            }
            return sbSql.ToString();
        }

        /// <summary>
        /// 获取从实体类更新到数据库的更新指令
        /// </summary>
        /// <param name="type"></param>
        /// <param name="connectionString"></param>
        /// <param name="providerName"></param>
        /// <returns></returns>
        public static string GetUpdateTableTextByType(Type type, string connectionString, string providerName)
        {
            // 检测实体类是否可用
            DBTableAttribute attrTable = type.GetCustomAttributes(typeof(DBTableAttribute), false).FirstOrDefault() as DBTableAttribute;
            if (attrTable != null && attrTable.Disabled) return string.Empty;

            // 表索引设置
            string sIndexConstraints = "";
            //if (attrTable.Clustered != null) sIndexConstraints += "CREATE CLUSTERED INDEX ci{0} ON {0} ({1});{2}".Fmt(type.Name, attrTable.Clustered, Environment.NewLine);
            //if (attrTable.Nonclustered != null) sIndexConstraints += "CREATE INDEX nci{0} ON {0} ({1});".Fmt(type.Name, attrTable.Nonclustered);
            if (sIndexConstraints.Length > 0) sIndexConstraints = "{0}{1}".Fmt(Environment.NewLine, sIndexConstraints);

            IDatabaseHelper dbh = new SQLServerHelper(connectionString);
            string dbType = "", name = "", length, sFieldName = dbh.SQL_FormatSql("[{0}]");
            string table = sFieldName.Fmt(type.Name);
            StringBuilder sbFields = new StringBuilder(), sbConstraint = new StringBuilder();
            DBColumnAttribute attrCol;
            IList<string> listFields = dbh.SO_GetFields(table);
            // ColOrder=字段序号,Name=字段名,IsIdentity=标识,KeyName=主键,DbType=类型,Length=占用字节数,Precision=长度,XScale=小数位数,AllowDBNull=允许空,DefaultValue=默认值,Common=字段说明
            IEnumerable<DataRow> dtSchema = dbh.ExecuteDataTable(dbh.Sql_GetShowStructureSql(table)).AsEnumerable();
            DataRow rSchema;
            foreach (FieldInfo fi in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic))
            {
                length = string.Empty;
                name = fi.Name.TrimStart('_');
                attrCol = fi.GetCustomAttributes(typeof(DBColumnAttribute), false).FirstOrDefault() as DBColumnAttribute;
                if (attrCol != null && !string.IsNullOrEmpty(attrCol.Length)) length = attrCol.Length;
                dbType = (attrCol != null && !string.IsNullOrEmpty(attrCol.DbType)) ? attrCol.DbType : dbh.ClrTypeToDbTypeName(fi.FieldType);
                if (listFields.Contains(name))
                {
                    rSchema = dtSchema.SingleOrDefault(a => a.Field<string>("Name") == name);
                    if (rSchema != null)
                    {
                        // 修改字段类型
                        if (rSchema["DbType"] != DBNull.Value && dbType != rSchema["DbType"].ToString()) sbConstraint.AppendFormat("alter table {0} modify {1} {2};{3}", table, name, dbType, Environment.NewLine);
                        // 修改字段长度
                        if (dbType.IsIn("varchar", "nvarchar") && length != rSchema["Precision"].ToString()) sbConstraint.AppendFormat("alter table {0} modify {1} {2}({3});{4}", table, name, dbType, length, Environment.NewLine);
                        // 删除主键
                        if (attrCol != null && !attrCol.IsKey && rSchema["KeyName"] != DBNull.Value) sbConstraint.AppendFormat("alter table {0} drop constraint {1};{2}", table, rSchema["KeyName"], Environment.NewLine);
                        // 添加主键
                        if (attrCol != null && attrCol.IsKey && rSchema["KeyName"] == DBNull.Value) sbConstraint.AppendFormat("alter table {0} add constraint PK_{0} primary key ({1});{2}", table, name, Environment.NewLine);
                        // 添加允许空
                        if (attrCol != null && attrCol.CanBeNull && rSchema.Field<string>("AllowDBNull") == "1") sbConstraint.AppendFormat("alter table {0} modify {1} {2}{3} null;{5}", table, name, dbType, dbType.IsIn("varchar", "nvarchar") ? string.Format("({0})", length) : string.Empty, Environment.NewLine);
                        // 取消允许空
                        if (attrCol != null && !attrCol.CanBeNull && rSchema.Field<string>("AllowDBNull") == "0") sbConstraint.AppendFormat("alter table {0} modify {1} {2}{3} not null;{5}", table, name, dbType, dbType.IsIn("varchar", "nvarchar") ? string.Format("({0})", length) : string.Empty, Environment.NewLine);

                        // 修改默认值(手动执行)
                        if (attrCol != null && attrCol.DefaultValue != rSchema.Field<string>("DefaultValue")) sbConstraint.AppendFormat("-- alter table {0} drop constraint DF_{0}_{1};{3}-- alter table {0} add constraint DF_{0}_{1} DEFAULT '{2}' for {1};{3}", table, name, attrCol.DefaultValue, Environment.NewLine);

                        // 修改列的说明
                        if (attrCol != null && attrCol.Common != rSchema.Field<string>("Common")) sbConstraint.AppendFormat("EXEC sp_updateextendedproperty 'MS_Description','{2}','user',dbo,'table','{0}','column',{1};{3}", table, name, attrCol.Common, Environment.NewLine);
                    }
                    listFields.Remove(name);
                    continue;
                }
                name = string.Format(sFieldName, name);
                if (dbType == "varchar" || dbType == "nvarchar")
                {

                    sbFields.AppendFormat(" {0} {1}({2})", name, dbType, length);
                    if (attrCol != null && !attrCol.CanBeNull) sbFields.Append(" not null");
                    if (attrCol != null && !string.IsNullOrEmpty(attrCol.DefaultValue)) sbFields.AppendFormat(" default '{0}'", attrCol.DefaultValue);
                    sbFields.Append(",");
                    continue;
                }
                if (dbType == "text" || dbType == "ntext" || dbType == "xml" || dbType == "uniqueidentifier")
                {
                    sbFields.AppendFormat(" {0} {1}", name, dbType);
                    if (attrCol != null && !attrCol.CanBeNull) sbFields.Append(" not null");
                    if (attrCol != null && !string.IsNullOrEmpty(attrCol.DefaultValue)) sbFields.AppendFormat(" default {1}{0}{1}", attrCol.DefaultValue, attrCol.DefaultValue.IndexOf("()") > -1 ? "" : "'");
                    sbFields.Append(",");
                    continue;
                }
                sbFields.AppendFormat(" {0} {1}", name, dbType);
                if (attrCol != null && !attrCol.CanBeNull) sbFields.Append(" not null");
                if (attrCol != null && !string.IsNullOrEmpty(attrCol.DefaultValue)) sbFields.AppendFormat(" default {0}", attrCol.DefaultValue);
                sbFields.Append(",");
            }
            string sDrop = "";
            StringBuilder sbRename = new StringBuilder();
            if (listFields.Count > 0)
            {
                sDrop = "-- alter table {0} drop column {1};{2}".Fmt(table, listFields.ToString(","), Environment.NewLine);
                foreach (string s in listFields)
                {
                    sbRename.AppendFormat("-- exec sp_rename '{0}.{1}', '', 'COLUMN';{2}", table, s, Environment.NewLine);
                }
            }
            string sAdd = sbFields.Length > 0 ? "{2}alter table {0} add {1};{2}".Fmt(table, sbFields.ToString().TrimEnd(','), Environment.NewLine) : "";
            return "{0}{1}{2}{3}".Fmt(sAdd, sDrop, sbRename.ToString(), (sAdd.Length > 0 || sDrop.Length > 0 || sbRename.Length > 0) ? sIndexConstraints : "");
        }

        /// <summary>
        /// 生成实体类代码
        /// </summary>
        /// <param name="connInfo"></param>
        /// <param name="tables"></param>
        /// <param name="imports"></param>
        /// <param name="copyright"></param>
        /// <param name="namespacename"></param>
        /// <param name="copyable">数据对拷字段对照特性</param>
        /// <returns></returns>
        public static Dictionary<string, string> GetCreateEntityText(string connectionString, string providerName, IList<string> tables, string imports = "using System;", string copyright = "", string namespacename = "", bool copyable = false)
        {
            if (copyright.Length > 0) copyright = string.Format("{1}{0}", Environment.NewLine, copyright);
            if (imports.Length > 0) imports = string.Format("{1}{0}{0}", Environment.NewLine, imports);

            Dictionary<string, string> list = new Dictionary<string, string>();
            StringBuilder sb = new StringBuilder();
            DataTable dt; object tblNote;
            string tabClass = "", tabField = "\t", ColumnSize, dbType, dbTypeN;
            IDatabaseHelper dbh = new SQLServerHelper(connectionString);
            foreach (string s in tables)
            {
                sb.Clear();
                // copyright
                sb.AppendLine(copyright.Length > 0 ? copyright.Replace("{name}", s).Replace("{date}", DateTime.Today.ToString("yyyy-MM-dd")) : copyright);
                // import namespace
                sb.Append(imports);

                if (namespacename.Length > 0)
                {
                    tabClass = "\t";
                    tabField = "\t\t";
                    sb.AppendFormat("namespace {0}", namespacename);
                    sb.AppendLine();
                    sb.AppendLine("{");
                }
                tblNote = dbh.ExecuteDataTable(dbh.SQL_GetShowTableCommonSql(s)).Rows[0][0];
                if (tblNote == DBNull.Value) tblNote = s;
                sb.AppendLine(string.Format("{0}/// <summary>", tabClass));
                sb.AppendLine(string.Format("{0}/// {1} 数据实体类", tabClass, tblNote));
                sb.AppendLine(string.Format("{0}/// </summary>", tabClass));
                sb.AppendFormat("{0}[DBTable(Common=\"{1}\"", tabClass, tblNote);
                if (copyable) sb.AppendFormat(" Source=\"{0}\"", s);
                sb.AppendFormat(")]{0}", Environment.NewLine);
                sb.AppendFormat("{2}public class {0}{1}", s, Environment.NewLine, tabClass);
                sb.AppendLine(string.Format("{0}{{", tabClass));
                dt = dbh.ExecuteDataTable(dbh.Sql_GetShowStructureSql(s));
                foreach (DataRow r in dt.Rows)
                {
                    sb.AppendLine(string.Format("{0}/// <summary>", tabField));
                    sb.AppendLine(string.Format("{0}/// {1}", tabField, (r["Common"] == DBNull.Value) ? r["Name"] : r["Common"]));
                    sb.AppendLine(string.Format("{0}/// </summary>", tabField));
                    dbTypeN = dbh.DbTypeNameToFieldTypeName(r["DbType"].ToString(), true);
                    dbType = dbTypeN.TrimEnd('?');
                    if (dbType == "string")
                    {
                        sb.AppendFormat("{3}public {0} {1} {{ get {{ return _{1}; }} set {{ _{1} = value; }} }}{2}{2}", dbType, r["Name"], Environment.NewLine, tabField);
                        ColumnSize = r["Precision"].ToString(); //MAX 数据类型返回正常的 4k，而对于 varchar，则为 8000
                        if (ColumnSize == "4k" || ColumnSize == "8000" || ColumnSize == "-1") ColumnSize = "Max";
                        sb.AppendFormat("{0}[DBColumn(Common=\"{1}\"", tabField, r["Name"]);
                        if (r["KeyName"] != DBNull.Value) sb.AppendFormat(", IsKey=true");
                        if (r["AllowDBNull"].ToString() == "1") sb.AppendFormat(", CanBeNull=true");
                        if (r["DefaultValue"] != DBNull.Value) sb.AppendFormat(", DefaultValue=\"{0}\"", r["DefaultValue"]);
                        if (copyable) sb.AppendFormat(", Source=\"{0}\"", r["Name"]);
                        sb.AppendFormat(", Length=\"{0}\"", ColumnSize);
                        sb.AppendFormat(")]{0}", Environment.NewLine);
                        sb.AppendFormat("{3}private {0} _{1};{2}{2}", dbTypeN, r["Name"], Environment.NewLine, tabField);
                    }
                    else
                    {
                        sb.AppendFormat("{3}public {0} {1} {{ get {{ return _{1} ?? default({0}); }} set {{ _{1} = value; }} }}{2}{2}", dbType, r["Name"], Environment.NewLine, tabField);
                        //IsAutoIncrement = dtSchema.Rows[i]["IsAutoIncrement"].ToString().ToBoolean();
                        //IsIdentity = dtSchema.Rows[i]["IsIdentity"].ToString().ToBoolean();
                        //IsExpression = dtSchema.Rows[i]["IsExpression"].ToString().ToBoolean();
                        sb.AppendFormat("{0}[DBColumn(Common=\"{1}\"", tabField, r["Name"]);
                        if (r["KeyName"] != DBNull.Value) sb.AppendFormat(", IsKey=true");
                        if (r["AllowDBNull"].ToString() == "1") sb.AppendFormat(", CanBeNull=true");
                        if (r["DefaultValue"] != DBNull.Value) sb.AppendFormat(", DefaultValue=\"{0}\"", r["DefaultValue"]);
                        if (copyable) sb.AppendFormat(", Source=\"{0}\"", r["Name"]);
                        sb.AppendFormat(")]{0}", Environment.NewLine);
                        sb.AppendFormat("{3}private {0} _{1};{2}{2}", dbTypeN, r["Name"], Environment.NewLine, tabField);
                    }
                }
                sb.AppendLine(string.Format("{0}}}", tabClass));
                if (namespacename.Length > 0) sb.AppendLine("}");
                list.Add(s, sb.ToString());
            }
            return list;
        }

        /// <summary>
        /// 生成商业逻辑层代码
        /// </summary>
        /// <param name="dllpath"></param>
        /// <param name="dllnamespace"></param>
        /// <param name="imports"></param>
        /// <param name="copyright"></param>
        /// <param name="namespacename"></param>
        /// <param name="prefix"></param>
        /// <returns></returns>
        public static Dictionary<string, string> GetCreateBLLText(string dllpath, string dllnamespace, string imports = "using System;", string copyright = "", string namespacename = "", string prefix = "")
        {
            Dictionary<string, string> dict = new Dictionary<string, string>();
            if (!File.Exists(dllpath)) return dict;
            if (copyright.Length > 0) copyright = string.Format("{1}{0}", Environment.NewLine, copyright);
            if (imports.Length > 0) imports = string.Format("{1}{0}{0}", Environment.NewLine, imports);

            StringBuilder sb;
            string tabClass = "", tabField = "\t", bizName;

            Assembly dll = Assembly.LoadFile(dllpath);
            foreach (Type t in dll.GetTypes())
            {
                if (t.Namespace != dllnamespace) continue;

                if (copyright.Length > 0) copyright = copyright.Replace("{name}", t.Name).Replace("{date}", DateTime.Today.ToString("yyyy-MM-dd"));
                sb = new StringBuilder();
                sb.AppendFormat("{0}{1}", copyright, imports);

                if (namespacename.Length > 0)
                {
                    tabClass = "\t";
                    tabField = "\t\t";
                    sb.AppendLine(string.Format("namespace {0}", namespacename));
                    sb.AppendLine("{");
                    sb.AppendLine("{0}using Entity;{1}".Fmt(tabClass, Environment.NewLine));
                }
                bizName = prefix.Length > 0 ? t.Name.TrimStart(prefix.ToCharArray()) : t.Name;
                sb.AppendLine(string.Format("{0}/// <summary>", tabClass));
                sb.AppendLine(string.Format("{0}/// {1} 商业逻辑类", tabClass, bizName));
                sb.AppendLine(string.Format("{0}/// </summary>", tabClass));
                sb.AppendFormat("{2}public class Biz{0} : UCL.DataBase.Demo.BusinessLogicBase{1}", bizName, Environment.NewLine, tabClass);
                sb.AppendLine(string.Format("{0}{{", tabClass));
                sb.AppendLine(string.Format("{0}/// <summary>", tabField));
                sb.AppendLine(string.Format("{0}/// 构造方法", tabField));
                sb.AppendLine(string.Format("{0}/// </summary>", tabField));
                sb.AppendLine(string.Format("{0}/// <param name=\"connectionName\"></param>", tabField));
                sb.AppendLine(string.Format("{0}public Biz{1}(System.Configuration.ConnectionStringSettings connectionInfo) : base(\"ID\", \"CreatedTime\", connectionInfo) {{ }}", tabField, bizName));
                sb.AppendLine(string.Format("{0}}}", tabClass));
                if (namespacename.Length > 0) sb.AppendLine("}");
                dict.Add(bizName, sb.ToString());
            }
            return dict;
        }

        /// <summary>
        /// 从程序集创建数据对拷的语句
        /// </summary>
        /// <param name="dllpath"></param>
        /// <param name="namespacetext"></param>
        /// <param name="fromdbowner"></param>
        /// <param name="todbowner"></param>
        /// <param name="types"></param>
        /// <returns></returns>
        public static Dictionary<string, string> GetCreateDataCopyTextByDll(string dllpath, string namespacetext, string fromdbowner, string todbowner, IList<string> types)
        {
            Dictionary<string, string> dict = new Dictionary<string, string>();
            if (!File.Exists(dllpath)) return dict;
            Assembly dll = Assembly.LoadFile(dllpath);
            foreach (Type t in dll.GetTypes())
            {
                if (t.Namespace != namespacetext) continue;
                if (types != null && types.Count > 0)
                {
                    if (!types.Contains(t.Name)) continue;
                }
                dict.Add(t.Name, GetCreateDataCopyTextByType(t, fromdbowner, todbowner));
            }
            return dict;
        }

        /// <summary>
        /// 从实体类创建数据对拷的语句
        /// </summary>
        /// <param name="t"></param>
        /// <param name="fromdbowner"></param>
        /// <param name="todbowner"></param>
        /// <returns></returns>
        public static string GetCreateDataCopyTextByType(Type t, string fromdbowner, string todbowner)
        {
            string fromtable = string.IsNullOrEmpty(fromdbowner) ? "[{0}]" : fromdbowner + ".[{0}]";
            string totable = string.IsNullOrEmpty(todbowner) ? "[{0}]".Fmt(t.Name) : "{0}.[{1}]".Fmt(todbowner, t.Name);
            bool hasAttr = false;
            string sfromtable = string.Empty, sfromfield = string.Empty;
            foreach (System.Attribute attr in t.GetCustomAttributes(false))
            {
                if (attr is DBTableAttribute)
                {
                    sfromtable = ((DBTableAttribute)attr).Source;
                    if (string.IsNullOrEmpty(sfromtable)) break;
                    hasAttr = true;
                    fromtable = fromtable.Fmt(sfromtable);
                }
            }
            if (!hasAttr) return string.Empty;
            StringBuilder sbFieldFrom = new StringBuilder();
            StringBuilder sbFieldTo = new StringBuilder();
            foreach (PropertyInfo pi in t.GetProperties())
            {
                hasAttr = false;
                foreach (System.Attribute attr in pi.GetCustomAttributes(false))
                {
                    if (attr is DBColumnAttribute)
                    {
                        sfromfield = ((DBColumnAttribute)attr).Source;
                        if (string.IsNullOrEmpty(sfromfield)) break;
                        hasAttr = true;
                        sbFieldFrom.AppendFormat("[{0}],", sfromfield);
                    }
                }
                if (hasAttr) sbFieldTo.AppendFormat("[{0}],", pi.Name);
            }
            return string.Format("Insert into {0} ({1}) select {2} from {3};".Fmt(totable, sbFieldTo.ToString().TrimEnd(','), sbFieldFrom.ToString().TrimEnd(','), fromtable));
        }

        public static string GetCreateInsertTextByType<T>(T e, string primaryKey = "ID", string providerName = "System.Data.SqlClient")
        {
            IList<DbParameter> lstParas = new List<DbParameter>();
            StringBuilder sbFields = new StringBuilder();
            StringBuilder sbValues = new StringBuilder();
            IDatabaseHelper dbh = new SQLServerHelper("");
            Type type = typeof(T);
            object oVal;
            DBColumnAttribute attrCol;
            DbParameter para;
            foreach (PropertyInfo pi in type.GetProperties())
            {
                oVal = pi.GetValue(e, null);
                if (oVal == null)
                {
                    if (pi.Name == primaryKey && (pi.PropertyType == typeof(int?) || pi.PropertyType == typeof(int))) continue; // 跳过自增长类型的主键字段
                    foreach (System.Attribute attr in pi.GetCustomAttributes(false))
                    {
                        attrCol = attr as DBColumnAttribute;
                        if (attrCol == null) break;
                        oVal = attrCol.DefaultValue;
                    }
                }
                if (oVal == null) continue;
                if ((pi.PropertyType == typeof(DateTime?) || pi.PropertyType == typeof(DateTime)) && oVal.ToString() == "Now") oVal = DateTime.Now;
                if ((pi.PropertyType == typeof(bool?) || pi.PropertyType == typeof(bool)))
                {
                    if (oVal.ToString() == "0") oVal = false;
                    if (oVal.ToString() == "1") oVal = true;
                }
                if ((pi.PropertyType == typeof(Guid?) || pi.PropertyType == typeof(Guid)))
                {
                    if (pi.Name == primaryKey && (oVal == null || oVal.ToString() == Guid.Empty.ToString())) oVal = Guid.NewGuid();
                    if (oVal.ToString() == "new()") oVal = Guid.NewGuid();
                    if (oVal.ToString() == "default") oVal = Guid.Empty;
                }
                sbFields.AppendFormat(" [{0}],", pi.Name);
                sbValues.AppendFormat(" @{0},", pi.Name);
                para = dbh.GetDbCommand().CreateParameter();
                para.ParameterName = "@{0}".Fmt(pi.Name);
                para.DbType = dbh.ClrTypeToDbType(pi.PropertyType);
                para.Value = oVal;
                lstParas.Add(para);
            }
            return "insert into [{0}] ({1}) values ({2})".Fmt(type.Name, sbFields.ToString().TrimEnd(','), sbValues.ToString().TrimEnd(','));
        }

        /// <summary>
        /// 获取主键字段
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static FieldInfo GetKeyField<T>()
        {
            DBColumnAttribute attrCol;
            foreach (FieldInfo fi in typeof(T).GetFields(BindingFlags.NonPublic | BindingFlags.Instance))
            {
                attrCol = fi.GetCustomAttributes(typeof(DBColumnAttribute), false).FirstOrDefault() as DBColumnAttribute;
                if (attrCol == null) continue;
                if (attrCol.IsKey) return fi;
            }
            return null;
        }
    }
}
